
#include "GLShaderManager.h"
/*
 `#include<GLShaderManager.h>` 移入了GLTool 着色器管理器（shader Mananger）类。没有着色器，我们就不能在OpenGL（核心框架）进行着色。着色器管理器不仅允许我们创建并管理着色器，还提供一组“存储着色器”，他们能够进行一些初步䄦基本的渲染操作。
 */

#include "GLTools.h"
/*
 `#include<GLTools.h>`  GLTool.h头文件包含了大部分GLTool中类似C语言的独立函数
*/

 
#include <GLUT/GLUT.h>
/*
 在Mac 系统下，`#include<glut/glut.h>`
 在Windows 和 Linux上，我们使用freeglut的静态库版本并且需要添加一个宏
*/

//定义一个，着色管理器
GLShaderManager shaderManager;

//简单的批次容器，是GLTools的一个简单的容器类。
GLBatch triangleBatch;

GLfloat blockSize = 0.1f;

GLfloat vVerts[] = {
    -blockSize,-blockSize,0.0f,
    blockSize,-blockSize,0.0f,
    blockSize,blockSize,0.0f,
    -blockSize,blockSize,0.0f
};

//x & y
GLfloat xPos = 0.0f;
GLfloat yPos = 0.0f;
/*
 在窗口大小改变时，接收新的宽度&高度。
 */
void changeSize(int w,int h)
{
    /*
      x,y 参数代表窗口中视图的左下角坐标，而宽度、高度是像素为表示，通常x,y 都是为0
     */
    glViewport(400, 300, w, h);
    
}

//普通计算
//void RenderScene(void)
//{
//    //1.执行清空颜色缓冲区  深度缓冲区（如有） 模板缓冲区（如有）
//    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
//    //2.绿色
//    GLfloat vGreen[] = {0.0f,1.0f,0.0f,1.0f};
//    //3.
//    shaderManager.UseStockShader(GLT_SHADER_IDENTITY,vGreen);
//    //4.
//    triangleBatch.Draw();
//
//    glutSwapBuffers();
//
//
//}
////普通计算方式
//void SpeacialKeys(int key,int x,int y)
//{
//    GLfloat stepSize = 0.025f;
//    //D点
//    GLfloat blockX = vVerts[9];
//    GLfloat blockY = vVerts[10];
//
//    if (key == GLUT_KEY_UP) {
//        blockY += stepSize;
//    }
//
//    if (key == GLUT_KEY_DOWN) {
//        blockY -= stepSize;
//    }
//
//    if (key == GLUT_KEY_LEFT) {
//        blockX -= stepSize;
//    }
//
//    if (key == GLUT_KEY_RIGHT) {
//        blockX += stepSize;
//    }
//    //边界检测
//    if (blockX < -1.0f) {
//        blockX = -1.0f;
//    }
//
//    if (blockX > 1.0f - blockSize * 2) {
//        blockX = 1.0f - - blockSize * 2;
//    }
//
//    if (blockY < -1.0f + blockSize * 2) {
//        blockY = -1.0f + blockSize * 2;
//    }
//
//    if (blockX > 1.0f) {
//        blockX = 1.0f ;
//    }
//
//
//
//    //更新其他顶点位置
//    //A点
//    vVerts[0] = blockX;
//    vVerts[1] = blockY - blockSize * 2;
//
//    //B点
//    vVerts[3] = blockX + blockSize * 2;
//    vVerts[4] = blockY - blockSize * 2;
//
//    //C点
//    vVerts[6] = blockX + blockSize * 2;
//    vVerts[7] = blockY;
//
//    //D点
//    vVerts[9] = blockX;
//    vVerts[10] = blockY;
//
//    triangleBatch.CopyVertexData3f(vVerts);
//
//    //提交
//    glutPostRedisplay();
//
//}

//矩阵方式
void RenderScene(void)
{
    glViewport(400, 400, 800, 800);
    //1.执行清空颜色缓冲区  深度缓冲区（如有） 模板缓冲区（如有）
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
    //2.绿色
    GLfloat vGreen[] = {0.0f,1.0f,0.0f,1.0f};

    //3创建一个4行4列的矩阵 x,y,z,w (w:缩放因子，默认为1.0)
    M3DMatrix44f mTransformMatrix;
    //矩阵平移
    m3dTranslationMatrix44(mTransformMatrix, xPos, yPos, 0.0f);
    //GLT_SHADER_FLAT 平面着色器 mTransformMatrix 平移效果 vGreen 颜色
    shaderManager.UseStockShader(GLT_SHADER_FLAT,mTransformMatrix,vGreen);
    //4.
    triangleBatch.Draw();

    glutSwapBuffers();


}

//矩阵方式 + 移动时旋转
//void RenderScene(void)
//{
//     glViewport(400, 400, 800, 800);
//    //1.执行清空颜色缓冲区  深度缓冲区（如有） 模板缓冲区（如有）
//    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
//    //2.绿色
//    GLfloat vGreen[] = {0.0f,1.0f,0.0f,1.0f};
//
//    //3创建一个4行4列的矩阵 x,y,z,w (w:缩放因子，默认为1.0)
//    M3DMatrix44f mTransformMatrix,mFinalTransform,mRotaionMatix;
//    //矩阵平移
//    m3dTranslationMatrix44(mTransformMatrix, xPos, yPos, 0.0f);
//    //GLT_SHADER_FLAT 平面着色器 mTransformMatrix 平移效果 vGreen 颜色
//    //矩阵旋转
//    static float ZRot = 0.0f;
//    ZRot += 5.0f;
//    /*
//     mRotaionMatix  旋转数据存在哪里
//     旋转角度(弧度)
//     x轴是否旋转
//     y轴是否旋转
//     z轴是否旋转
//     */
//    m3dRotationMatrix44(mRotaionMatix, m3dDegToRad(ZRot), 0.0f, 0.0f, 1.0f);
//    //矩阵相乘
//    m3dMatrixMultiply44(mFinalTransform, mTransformMatrix, mRotaionMatix);
//    shaderManager.UseStockShader(GLT_SHADER_FLAT,mFinalTransform,vGreen);
//    //4.
//    triangleBatch.Draw();
//
//    glutSwapBuffers();
//
//
//}

//矩阵方式
void SpeacialKeys(int key,int x,int y){
    GLfloat stepSize = 0.025f;
    if (key == GLUT_KEY_UP) {
           yPos += stepSize;
       }

       if (key == GLUT_KEY_DOWN) {
           yPos -= stepSize;
       }

       if (key == GLUT_KEY_LEFT) {
           xPos -= stepSize;
       }

       if (key == GLUT_KEY_RIGHT) {
           xPos += stepSize;
       }

//    //边界检测
    if (xPos < -1.0f + blockSize) { //相对初始位置，向左移动的极值
        xPos = -1.0f + blockSize;
    }

    if (xPos > 1.0f - blockSize) { //相对初始位置，向右移动的极值
        xPos = 1.0f - blockSize;
    }

    if (yPos > 1.0f - blockSize) { //相对初始位置，向上移动的极值
        yPos = 1.0f - blockSize;
    }

    if (yPos < -1.0f + blockSize) { //相对初始位置，向下移动的极值
        yPos = -1.0f + blockSize;
    }

    //提交
       glutPostRedisplay();
}

void setupRC()
{
    //清理窗口颜色
    glClearColor(0.98f, 0.40f, 0.7f, 1.0);
    //初始化着色器管理器
    shaderManager.InitializeStockShaders();
    // 指定定点
//    GLfloat vVerts[] = {
//        -0.5f,0.0f,0.0f,
//        0.5,0.0f,0.0f,
//        0.0f,0.5f,0.0f
//    };
    
    //primitive 用不同的模式啦绘制  GL_TRIANGLES  三角形模式
//    triangleBatch.Begin(GL_TRIANGLES, 3);
    triangleBatch.Begin(GL_TRIANGLE_FAN, 4);
    //将顶点数据copy进去
    triangleBatch.CopyVertexData3f(vVerts);
    //结束
    triangleBatch.End();
    
    
}

int main(int argc,char *argv[])
{
    //设置当前工作目录，针对MAC OS X
    /*
     `GLTools`函数`glSetWorkingDrectory`用来设置当前工作目录。实际上在Windows中是不必要的，因为工作目录默认就是与程序可执行执行程序相同的目录。但是在Mac OS X中，这个程序将当前工作文件夹改为应用程序捆绑包中的`/Resource`文件夹。`GLUT`的优先设定自动进行了这个中设置，但是这样中方法更加安全。
     */
    gltSetWorkingDirectory(argv[0]);
    
    
    //初始化GLUT库,这个函数只是传说命令参数并且初始化glut库
    glutInit(&argc, argv);
    
    
    glutInitDisplayMode(GLUT_RGBA);
    
    //GLUT窗口大小、窗口标题
    glutInitWindowSize(800, 800);
    glutCreateWindow("Triangle");
    
    
    /*
     GLUT 内部运行一个本地消息循环，拦截适当的消息。然后调用我们不同时间注册的回调函数。我们一共注册2个回调函数：
     1）为窗口改变大小而设置的一个回调函数
     2）包含OpenGL 渲染的回调函数
     */
    
    //注册重塑函数
    glutReshapeFunc(changeSize);
    //注册显示函数
    glutDisplayFunc(RenderScene);

    glutSpecialFunc(SpeacialKeys);
    
    /*
     初始化一个GLEW库,确保OpenGL API对程序完全可用。
     在试图做任何渲染之前，要检查确定驱动程序的初始化过程中没有任何问题
     */
    GLenum status = glewInit();
    if (GLEW_OK != status) {
        
        printf("GLEW Error:%s\n",glewGetErrorString(status));
        return 1;
        
    }
    
    //设置我们的渲染环境
    setupRC();
    
    glutMainLoop();
    
    return  0;
    
}
